package com.corner.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.corner.common.core.domain.entity.SysUser;
import com.corner.common.core.domain.model.LoginBody;
import com.corner.common.exception.GlobalException;
import com.corner.common.utils.wx.WXPayXmlUtil;
import com.corner.system.domain.GzhUserinfo;
import com.corner.system.mapper.GzhUserinfoMapper;
import com.corner.system.mapper.SysUserMapper;
import com.corner.system.service.WxgzhService;
import com.corner.system.utils.WXPayUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutImageMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutNewsMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
public class WxgzhServiceImpl implements WxgzhService
{

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    SysUserMapper userMapper;

    @Value("${GZH_TOKEN}")
    public String gzhToken;

    @Value("${GZH_APPID}")
    public String appId;

    @Value("${GZH_SECRET}")
    public String appSecret;

    /**补贴领取方式图片*/
    @Value("${IMG.BUTIE_MEDIA_ID}")
    public String butieImgMediaId;

    /**
     * 获取基础ACCESSTOKEN
     * @return
     */
    @Override
    public String getAccessToken() {
        //从缓存中拿取AccessToken
        Boolean hasAccess = this.redisTemplate.hasKey("GZH_ACCESS_TOKEN");
        if(hasAccess){
            Long wx_access_token = this.redisTemplate.getExpire("GZH_ACCESS_TOKEN", TimeUnit.SECONDS);
            //如果剩余有效时间大于30秒
            if(wx_access_token > 30){
                String accessToken = (String) redisTemplate.boundHashOps("GZH_ACCESS_TOKEN").get("access_token");
                return accessToken;
            }
        }
        //如果缓存中没有或剩余有效时间不足30秒，重新获取
        //删除原有Key
        redisTemplate.delete("GZH_ACCESS_TOKEN");
        //调用获取
        //String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx6fce5cfce1ddf3f3&secret=2799d6c91d7a66e30bee5e191c3e3203";
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+appSecret;
        String result = restTemplate.getForObject(url, String.class);
        Map<String,String> resultMap = (Map) JSON.parse(result);

        String access_token = resultMap.get("access_token");
        long expires_in = Long.valueOf(String.valueOf(resultMap.get("expires_in")));
        //AccessToken存入缓存
        this.redisTemplate.boundHashOps("GZH_ACCESS_TOKEN").put("access_token",access_token);
        this.redisTemplate.boundHashOps("GZH_ACCESS_TOKEN").put("expires_in",expires_in);
        //设置缓存过期时间与AccessToken过期时间相同
        this.redisTemplate.expire("GZH_ACCESS_TOKEN", expires_in, TimeUnit.SECONDS);
        return access_token;
    }

    /**
     * 获取网页授权ACCESSTOKEN
     * @return
     */
    @Override
    public Map<String,String> getUrlAccessToken(String code, String username) {
        log.info("获取code{}"+code);
        Map tokenAndOpenid = new HashMap();
        /*String theKey = "GZH_URL_ACCESS_TOKEN:" + username;
        //从缓存中拿取AccessToken
        Boolean hasAccess = this.redisTemplate.hasKey(theKey);
        Map tokenAndOpenid = new HashMap();
        if(hasAccess){
            Long wx_access_token = this.redisTemplate.getExpire(theKey, TimeUnit.SECONDS);
            //如果剩余有效时间大于30秒
            if(wx_access_token > 30){
                String accessToken = (String) redisTemplate.boundHashOps(theKey).get("access_token");
                String openid = (String) redisTemplate.boundHashOps(theKey).get("openid");

                tokenAndOpenid.put("accessToken",accessToken);
                tokenAndOpenid.put("openid",openid);
                return tokenAndOpenid;
            }
        }
        //如果缓存中没有或剩余有效时间不足30秒，重新获取
        //删除原有Key
        redisTemplate.delete(theKey);*/
        //调用获取
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appId+"&secret="+appSecret+"&code="+code+"&grant_type=authorization_code";
        String result = restTemplate.getForObject(url, String.class);
        Map resultMap = (Map) JSON.parse(result);

        String access_token = (String)resultMap.get("access_token");
        if(StringUtils.isBlank(access_token)){
            throw new GlobalException("获取access_token失败,错误码："+(Integer)resultMap.get("errcode")+"---"+(String)resultMap.get("errmsg"));
        }
        String openid = (String)resultMap.get("openid");
        /*long expires_in = Long.valueOf(String.valueOf(resultMap.get("expires_in")));
        //AccessToken存入缓存
        this.redisTemplate.boundHashOps(theKey).put("access_token",access_token);
        this.redisTemplate.boundHashOps(theKey).put("expires_in",expires_in);
        this.redisTemplate.boundHashOps(theKey).put("openid",openid);
        tokenAndOpenid.put("accessToken",access_token);
        tokenAndOpenid.put("openid",openid);
        //设置缓存过期时间与AccessToken过期时间相同
        this.redisTemplate.expire(theKey, expires_in, TimeUnit.SECONDS);*/
        tokenAndOpenid.put("accessToken",access_token);
        tokenAndOpenid.put("openid",openid);
        return tokenAndOpenid;
    }
    /**
     * 获取JsapiTicket
     * @return
     */
    @Override
    public String getJsapiTicket() {
        //从缓存中拿取AccessToken
        Boolean ticket = this.redisTemplate.hasKey("GZH_JSAPI_TICKET");
        if(ticket){
            Long gzh_jsapi_ticket = this.redisTemplate.getExpire("GZH_JSAPI_TICKET", TimeUnit.SECONDS);
            //如果剩余有效时间大于30秒
            if(gzh_jsapi_ticket > 30){
                String jsapiTicket = (String) redisTemplate.boundHashOps("GZH_JSAPI_TICKET").get("jsapi_ticket");
                return jsapiTicket;
            }
        }
        //如果缓存中没有或剩余有效时间不足30秒，重新获取
        //删除原有Key
        redisTemplate.delete("GZH_JSAPI_TICKET");

        String accessToken = getAccessToken();
        //调用获取
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi";
        String result = restTemplate.getForObject(url, String.class);
        Map<String,String> resultMap = (Map) JSON.parse(result);

        String jsapiTicket = resultMap.get("access_token");
        long expires_in = Long.valueOf(String.valueOf(resultMap.get("expires_in")));
        //AccessToken存入缓存
        this.redisTemplate.boundHashOps("GZH_JSAPI_TICKET").put("ticket",jsapiTicket);
        this.redisTemplate.boundHashOps("GZH_JSAPI_TICKET").put("expires_in",expires_in);
        //设置缓存过期时间与AccessToken过期时间相同
        this.redisTemplate.expire("GZH_JSAPI_TICKET", expires_in, TimeUnit.SECONDS);
        return jsapiTicket;
    }

    @Override
    public String getSignature(String timestamp, String noncestr, String url) {
        String jsapiTicket = this.getJsapiTicket();
        noncestr = "noncestr=" + noncestr;
        jsapiTicket = "jsapi_ticket=" + jsapiTicket;
        timestamp = "timestamp=" + timestamp;
        url = "url=" + url;

        String s = sort1(noncestr, jsapiTicket, timestamp, url);
        return decriptSHA1(s);

    }


    /**
     * 判断来源是否是微信服务器
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @return
     */
    public Boolean wxSignatureCheck(String signature, String timestamp, String nonce, String echostr) {

        //排序
        String sortString = sort(gzhToken, timestamp, nonce);
        //加密
        String mytoken = decriptSHA1(sortString);
        //校验签名
        if (mytoken != null && mytoken != "" && mytoken.equals(signature)) {
            System.out.println("签名校验通过。");
            return true; //如果检验成功输出echostr，微信服务器接收到此输出，才会确认检验完成。
        } else {
            System.out.println("签名校验失败。");
            return false;
        }
    }




    @Override
    public String getUserMessage(HttpServletRequest request, HttpServletResponse response) {
        String messageToUser = "";
        try {

/*            Map<String, String> data = new HashMap<String, String>();
            InputStream inputStream = request.getInputStream();
            DocumentBuilder documentBuilder = WXPayXmlUtil.newDocumentBuilder();
            org.w3c.dom.Document doc = documentBuilder.parse(inputStream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                inputStream.close();
            } catch (Exception ex) {
                // do nothing
            }
            System.out.println(data.toString());*/

            WxMpXmlMessage message = WxMpXmlMessage.fromXml(request.getInputStream());

            //用户发送普通消息
            if(message.getMsgType().equals("text")){
                System.out.println("来自用户"+message.getFromUserName()+"发来消息："+message.getContent());
                messageToUser = receiveText(message,"您好，老纳暂时无法处理您的信息");
            // 用户发送事件
            }else if(message.getMsgType().equals("event")){
                log.info("用户发送事件");
                messageToUser = eventMessage(message);
                log.info("返回平台xml{}"+messageToUser);
            }
        } catch (Exception e) {
            e.printStackTrace();

        }
        return messageToUser;
    }


    @Override
    public void publicMsg(Map requestMap){
        String accessToken = getAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken;
        ResponseEntity<String> responseEntity =
                restTemplate.postForEntity(url, requestMap, String.class);
        String body = responseEntity.getBody();
        System.out.println(body);

    }

    /**
     * 查看用户是否关注公众号
     * @param
     * @return
     */
    @Override
    public void checkUserIfSubscribe(String openid) {

        SysUser sysUser = this.selectUserInfo(openid);
        if(sysUser == null){
            throw new RuntimeException("用户未关注公众号");
        }
    /*
        List<Map<String, String>> playerContact = playerMapper.getPlayerContact(user.getUserId());
        return playerContact.get(0);*/
    }


    /**
     * 获取用户UnionID
     * @param openId
     */
    @Override
    public Map<String,Object> getUserInfo(String openId){
        Map<String,Object> resultBody = null;
        String accessToken = getAccessToken();
        //accessToken ="74_kRS98qJ7AgN_NDzPnAMe9jsXN_3P4Vo258B1OyQ-q8jnYExrdpWo3GH8dBjhYBTOUI5oQlmpcN3jEe2deV0oCvrPtAdcFRF1hD1tWFqS7Qny8meIQXxKHXA8IiMXETgABAOVK";
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";
        ResponseEntity<String> responseEntity =
                restTemplate.getForEntity(url, String.class);
        String body = responseEntity.getBody();
        System.out.println(body);
        resultBody = JSON.parseObject(body,Map.class);
        if("42001".equals(resultBody.get("errcode")+"")){
            redisTemplate.delete("GZH_ACCESS_TOKEN");
            resultBody = this.getUserInfo(openId);
        }
        return resultBody;
    }




    /**
     * 创建个性化菜单
     */
    @Override
    public void createSelfMenu() {
        String accessToken = getAccessToken();
        //String url = "https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token="+accessToken;
        String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="+accessToken;
        Map requestMap = new HashMap<>();
        List buttons = new ArrayList<>();
        Map btn = new HashMap();
        btn.put("type","miniprogram");
        btn.put("name","进入小程序");
        btn.put("url","https://www.caogener.cn/");
        btn.put("appid",appId);
        btn.put("pagepath","pages/index/index");
        buttons.add(btn);
        //requestMap.put("access_token",accessToken);
        requestMap.put("button",buttons);
        requestMap.put("matchrule",new HashMap());

        ResponseEntity<String> responseEntity =
                restTemplate.postForEntity(url, requestMap, String.class);
        String body = responseEntity.getBody();
        System.out.println(body);
    }

    @Override
    public Map selectSubscribeUser() {
        String accessToken = getAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token="+accessToken;
        Map requestMap = new HashMap<>();

        ResponseEntity<String> responseEntity =
                restTemplate.getForEntity(url, String.class);
        String body = responseEntity.getBody();
        System.out.println(body);
        return JSON.parseObject(body,Map.class);
    }

    @Override
    public SysUser selectUserInfo(String openid) {
        SysUser select = userMapper.selectByOpenId(openid);
        return select;
    }

    @Override
    public void insertUserInfo(GzhUserinfo userinfo) {

    }

    @Override
    public void updateUserInfo(GzhUserinfo userinfo) {

    }


    /**
     * 接收事件推送
     * @param message
     */
    private String eventMessage( WxMpXmlMessage message){
        String messageToUser = null;
        String event = message.getEvent();
        String fromUserName = message.getFromUserName();
        //用户订阅
        if(event.equals("subscribe")){
            log.info("用户{}关注公众号",fromUserName);

            String openId = fromUserName;
            Map<String, Object> resultBody = getUserInfo(openId);
            if(resultBody.get("errcode")!=null){
                throw new RuntimeException("获取用户信息失败！");
            }
            SysUser userinfo = new SysUser();
            userinfo.setAppId(appId);
            userinfo.setSubscribe(resultBody.get("subscribe").toString());
            userinfo.setOpenId((String)resultBody.get("openid"));
            userinfo.setLanguage((String)resultBody.get("language"));
            Long subscribeTime = Long.valueOf(resultBody.get("subscribe_time").toString());
            userinfo.setSubscribeTime(new Date(subscribeTime));
            userinfo.setUnionId((String)resultBody.get("unionid"));
            userinfo.setRemark((String)resultBody.get("remark"));
            userinfo.setGroupId(resultBody.get("groupid").toString());
            userinfo.setTagidList(resultBody.get("tagid_list").toString());
            userinfo.setSubscribeScene((String)resultBody.get("subscribe_scene"));
            userinfo.setQrScene(resultBody.get("qr_scene").toString());
            userinfo.setQrSceneStr(resultBody.get("qr_scene_str").toString());
            userinfo.setDelFlag("0");
            //查询数据库是否留有此用户信息
            SysUser user1 = userMapper.selectByOpenIdIgnoreDel(openId);
            if(user1 == null){
                userinfo.setCreateTime(new Date());
                userMapper.insertUser(userinfo);
            }else{
                userinfo.setUserId(user1.getUserId());
                userinfo.setUpdateTime(new Date());
                userinfo.setUpdateBy("重新关注");
                userMapper.updateUser(userinfo);
            }
            String content = "您好，感谢关注凯纳智慧生态！";
            //创建返回消息
            //messageToUser = sendTextMessageToUser((String) resultBody.get("openid"), "448751194", content);

            //文本
            //messageToUser = receiveText(message,content);

            //图片
//            messageToUser = receiveImage(message, butieImgMediaId);

            //图文
            messageToUser = receiveImageAndText(message);
            //用户取消订阅
        }else if(event.equals("unsubscribe")){
            log.info("用户{}取消关注公众号",fromUserName);
            String openId = fromUserName;
            int i = userMapper.unfollow(openId);
            log.info("删除用户信息");

            //用户点击“联系我们”自定义菜单
        }else if(event.equals("CLICK")){
            if(message.getEventKey().equals("CONTACT_US")){
                messageToUser = receiveText(message,"服务热线：400-655-1155（工作时间：8:30~17:00）");
            }
        }
        return messageToUser;
    }

    /**
     * 给用户发送文本消息
     */
    private String sendTextMessageToUser(String toUser,String fromUser,String content){
        /*Map v = new LinkedHashMap();
        v.put("MediaId","234sd#S");
        v.put("Title","标题");
        String vs = null;
        try {
            vs = WXPayUtil.mapToXmlNoHead(v,false);
        } catch (Exception e) {
            e.printStackTrace();
        }*/
        Map m1 = new LinkedHashMap();
        /*m1.put("ToUserName","<![CDATA["+ toUser +"]]>");
        m1.put("FromUserName","<![CDATA["+ fromUser +"]]>");
        m1.put("CreateTime","1231245");
        m1.put("MsgType","<![CDATA[text]]>");
        m1.put("Content","<![CDATA["+ content +"]]>");*/
        m1.put("ToUserName",toUser );
        m1.put("FromUserName", fromUser );
        Date date = new Date();
        long time = date.getTime();
        m1.put("CreateTime",time);
        m1.put("MsgType","text");
        m1.put("Content",content);
        String xml = null;
        try {
            xml = WXPayUtil.mapToXmlNoHead(m1,true);
            xml ="<xml>\n" +
                    "\t<ToUserName>"+toUser+"</ToUserName>\n" +
                    "\t<FromUserName>"+fromUser+"</FromUserName>\n" +
                    "\t<CreateTime>"+time+"</CreateTime>\n" +
                    "\t<MsgType>"+"text"+"</MsgType>\n" +
                    "\t<Content>"+content+"</Content>\n" +
                    "\t<MsgId>"+"1234567890123456"+"</MsgId>\n" +
                    "</xml>\n";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return xml;
    }
    @Override
    public String receiveText(WxMpXmlMessage message, String content) {

        String str="";
        String fromUserName = message.getFromUserName();
        String toUserName = message.getToUserName();
        //文本消息  文本内容
        //String content = message.getContent();

        //将回复消息按格式封装成xml
        //toUser(fromUserName).fromUser(toUserName)  发送者变成接受者
        WxMpXmlOutTextMessage text = WxMpXmlOutTextMessage.TEXT().toUser(fromUserName).fromUser(toUserName).content(content ).build();
        //WxMpXmlOutImageMessage imageMessage = WxMpXmlOutTextMessage.IMAGE().toUser(fromUserName).fromUser(toUserName).mediaId().build();
        str = text.toXml();
        return str;
    }

    public String receiveImage(WxMpXmlMessage message, String mediaId) {

        String str="";
        String fromUserName = message.getFromUserName();
        String toUserName = message.getToUserName();
        //将回复消息按格式封装成xml
        WxMpXmlOutImageMessage imageMessage = WxMpXmlOutTextMessage.IMAGE().toUser(fromUserName).fromUser(toUserName).mediaId(mediaId).build();
        str = imageMessage.toXml();
        return str;
    }

    public String receiveImageAndText(WxMpXmlMessage message) {

        WxMpXmlOutNewsMessage.Item item = new WxMpXmlOutNewsMessage.Item();
        item.setDescription("点击了解领取补贴具体步骤");
        item.setPicUrl("https://mmbiz.qpic.cn/sz_mmbiz_png/INrmJ2VDticiab96iajIlkjXuibdO9VhU8GH3ic2Ke0sOru39II2rhTOlzPlV1dQwoicKBh1J8wSfd5cqnScHZulsBDg/640?wx_fmt=png");
        item.setTitle("感谢关注凯纳智慧生态！");
        item.setUrl("https://mp.weixin.qq.com/s?__biz=Mzg5ODg5MTcyMg==&mid=2247483666&idx=1&sn=3c7cf128857607e1a562ef1faf5786f9&chksm=c05aebb7f72d62a1eb98e578ac34f9e879ec5605e31f2acc9ba6075780f77b1885bdd0f04f78#rd");
        String str="";
        String fromUserName = message.getFromUserName();
        String toUserName = message.getToUserName();
        //将回复消息按格式封装成xml
        WxMpXmlOutNewsMessage build = WxMpXmlOutTextMessage.NEWS().toUser(fromUserName).fromUser(toUserName).addArticle(item).build();
        str = build.toXml();
        return str;
    }



    /**
     * 排序方法
     * @param token
     * @param timestamp
     * @param nonce
     * @return
     */
    private static String sort(String token, String timestamp, String nonce) {
        String[] strArray = { token, timestamp, nonce };
        Arrays.sort(strArray);

        StringBuilder sbuilder = new StringBuilder();
        for (String str : strArray) {
            sbuilder.append(str);
        }

        return sbuilder.toString();
    }

    /**
     * 排序方法
     * @param noncestr
     * @param jsapiTicket
     * @param timestamp
     * @param url
     * @return
     */
    private static String sort1(String noncestr,String jsapiTicket,String timestamp,String url) {
        String[] strArray = { noncestr, jsapiTicket, timestamp, url };
        Arrays.sort(strArray);

        StringBuilder sbuilder = new StringBuilder();
        for (int i = 0; i < strArray.length; i++) {
            sbuilder.append(strArray[i]);
            if(i != strArray.length){
                sbuilder.append("&");
            }

        }

        return sbuilder.toString();
    }





    private String decriptSHA1(String decript){
        try {
            MessageDigest digest = MessageDigest
                    .getInstance("SHA-1");
            digest.update(decript.getBytes());
            byte messageDigest[] = digest.digest();
            // Create Hex String
            StringBuffer hexString = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    private static Pattern UNDERLINE_PATTERN = Pattern.compile("_([a-z])");

    public String underlineToHump (String str){
        //正则匹配下划线及后一个字符，删除下划线并将匹配的字符转成大写
        Matcher matcher = UNDERLINE_PATTERN.matcher(str);
        StringBuffer sb = new StringBuffer(str);
        if (matcher.find()) {
            sb = new StringBuffer();
            //将当前匹配的子串替换成指定字符串，并且将替换后的子串及之前到上次匹配的子串之后的字符串添加到StringBuffer对象中
            //正则之前的字符和被替换的字符
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
            //把之后的字符串也添加到StringBuffer对象中
            matcher.appendTail(sb);
        } else {
            //去除除字母之外的前面带的下划线
            return sb.toString().replaceAll("_", "");
        }
        return underlineToHump(sb.toString());
    }



}
